package com.lagou.rpc.consumer.proxy;

import com.alibaba.fastjson.JSON;
import com.lagou.rpc.common.RpcRequest;
import com.lagou.rpc.common.RpcResponse;
import com.lagou.rpc.consumer.ServerRequestCostTimeCache;
import com.lagou.rpc.consumer.client.RpcClient;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 客户端代理类-创建代理对象
 * 1.封装request请求对象
 * 2.创建RpcClient对象
 * 3.发送消息
 * 4.返回结果
 */
public class RpcClientProxy {
    private static Map<String, RpcClient> server2RpcClientMap = new ConcurrentHashMap<>();

    public static Object createProxy(Class serviceClass, String ip, int port) {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                new Class[]{serviceClass}, new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //1.封装request请求对象
                        RpcRequest rpcRequest = new RpcRequest();
                        rpcRequest.setRequestId(UUID.randomUUID().toString());
                        rpcRequest.setClassName(method.getDeclaringClass().getName());
                        rpcRequest.setMethodName(method.getName());
                        rpcRequest.setParameterTypes(method.getParameterTypes());
                        rpcRequest.setParameters(args);
                        //2.创建RpcClient对象
                        //之前是每次new一个新的RpcClient，这里不能new了，而是要从所有有效的RpcClient列表中选出一个合适的发送
                        RpcClient rpcClient = findRpcClient(ip, port);
                        try {
                            //3.发送消息
                            // 每次消息发送前，记录一次开始时间
                            long beginTime = System.currentTimeMillis();
                            Object responseMsg = rpcClient.send(JSON.toJSONString(rpcRequest));
                            // 拿到响应结果，记录一次结束时间
                            long endTime = System.currentTimeMillis();
                            // 计算请求耗时，保存下来
                            long cost = endTime - beginTime;
                            System.out.println(ip + ":" + port + "响应时间:" + cost + "ms");
                            ServerRequestCostTimeCache.update(ip + ":" + port, cost);
                            RpcResponse rpcResponse = JSON.parseObject(responseMsg.toString(), RpcResponse.class);
                            if (rpcResponse.getError() != null) {
                                throw new RuntimeException(rpcResponse.getError());
                            }
                            //4.返回结果
                            Object result = rpcResponse.getResult();
                            return JSON.parseObject(result.toString(), method.getReturnType());
                        } catch (Exception e) {
                            throw e;
                        }
                    }
                });
    }


    public static void addRpcClient(String ip, int port) {
        server2RpcClientMap.put(generateKey(ip, port), new RpcClient(ip, port));
    }

    public static void removeRpcClient(String key) {
        server2RpcClientMap.remove(key);
    }

    private static RpcClient findRpcClient(String ip, int port) {
        return server2RpcClientMap.get(generateKey(ip, port));
    }

    private static String generateKey(String ip, int port) {
        return ip + ":" + port;
    }
}
